package se.webbzon.oschi01.nbt;

import java.util.Iterator;

import se.webbzon.oschi01.utils.ObjectUtils;

public class Tags {
	
	public static final byte TAG_END = (byte) 0;
	public static final byte TAG_BYTE = (byte) 1;
	public static final byte TAG_SHORT = (byte) 2;
	public static final byte TAG_INT = (byte) 3;
	public static final byte TAG_LONG = (byte) 4;
	public static final byte TAG_FLOAT = (byte) 5;
	public static final byte TAG_DOUBLE = (byte) 6;
	public static final byte TAG_BYTE_ARRAY = (byte) 7;
	public static final byte TAG_STRING = (byte) 8;
	public static final byte TAG_LIST = (byte) 9;
	public static final byte TAG_COMPOUND = (byte) 10;
	public static final byte TAG_INT_ARRAY = (byte) 11;
	
	public static boolean isEndTag(Tag<?> tag) {
		return tag.getFactory().getId() == TAG_END;
	}
	
	public static boolean isByteTag(Tag<?> tag) {
		return tag.getFactory().getId() == TAG_BYTE;
	}
	
	public static boolean isShortTag(Tag<?> tag) {
		return tag.getFactory().getId() == TAG_SHORT;
	}
	
	public static boolean isIntTag(Tag<?> tag) {
		return tag.getFactory().getId() == TAG_INT;
	}
	
	public static boolean isLongTag(Tag<?> tag) {
		return tag.getFactory().getId() == TAG_LONG;
	}
	
	public static boolean isFloatTag(Tag<?> tag) {
		return tag.getFactory().getId() == TAG_FLOAT;
	}
	
	public static boolean isDoubleTag(Tag<?> tag) {
		return tag.getFactory().getId() == TAG_DOUBLE;
	}
	
	public static boolean isByteArrayTag(Tag<?> tag) {
		return tag.getFactory().getId() == TAG_BYTE_ARRAY;
	}
	
	public static boolean isStringTag(Tag<?> tag) {
		return tag.getFactory().getId() == TAG_STRING;
	}
	
	public static boolean isListTag(Tag<?> tag) {
		return tag.getFactory().getId() == TAG_LIST;
	}
	
	public static boolean isCompoundTag(Tag<?> tag) {
		return tag.getFactory().getId() == TAG_COMPOUND;
	}
	
	public static boolean isIntArrayTag(Tag<?> tag) {
		return tag.getFactory().getId() == TAG_INT_ARRAY;
	}
	
	public static final String getPath(Tag<?> tag) {
		String name = tag.toString();
		if (name == null || name.isEmpty())
			name = "<noname>";
		
		if (tag.hasParent())
			return getPath(tag.getParent()) + "\\" + name;
		else
			return name;
	}
	
	public static final <T> TagGeneration<T> unmodifiableGeneration(final TagGeneration<T> generation) {
		return new TagGeneration<T>() {

			@Override public Iterator<Tag<T>> iterator() {
				final Iterator<Tag<T>> it = generation.iterator();
				return new Iterator<Tag<T>>() {

					@Override public boolean hasNext() {
						return it.hasNext();
					}

					@Override public Tag<T> next() {
						return unmodifiableTag(it.next());
					}

					@Override public void remove() {
						throw new UnsupportedOperationException();
					}
					
				};
			}

			@Override public boolean isEmpty() {
				return generation.isEmpty();
			}

			@Override public int siblings() {
				return generation.siblings();
			}

			@Override public Tag<T> getSibling(int index) {
				return unmodifiableTag(generation.getSibling(index));
			}

			@Override public int indexOf(Tag<T> sibling) {
				return generation.indexOf(sibling);
			}

			@Override public boolean addSibling(Tag<T> sibling) {
				throw new UnsupportedOperationException();
			}

			@Override public boolean addSibling(Tag<T> sibling, int index) {
				throw new UnsupportedOperationException();
			}

			@Override public boolean removeSibling(Tag<T> sibling) {
				throw new UnsupportedOperationException();
			}

			@Override public boolean removeSibling(int index) {
				throw new UnsupportedOperationException();
			}

			@Override public void clear() {
				throw new UnsupportedOperationException();
			}
			
			@Override public boolean equals(Object o) {
				return ObjectUtils.equals(TagGeneration.class, generation, o);
			}
			
		};
	}
	
	public static final TagSibling unmodifiableSibling(final TagSibling sibling) {
		return new TagSibling() {

			@Override public boolean hasParent() {
				return sibling.hasParent();
			}

			@Override public Tag<?> getParent() {
				return sibling.getParent();
			}

			@Override public boolean hasChildren() {
				return sibling.hasChildren();
			}

			@Override public TagGeneration<?> getChildren() {
				return unmodifiableGeneration(sibling.getChildren());
			}

			@Override public TagGeneration<?> getGeneration() {
				return unmodifiableGeneration(sibling.getGeneration());
			}

			@Override public TagSibling getSibling() {
				return unmodifiableSibling(sibling.getSibling());
			}

			@Override public void setSibling(TagSibling sibling) {
				throw new UnsupportedOperationException();
			}
			
			@Override public boolean equals(Object o) {
				return ObjectUtils.equals(TagSibling.class, sibling, o);
			}
			
		};
	}
	
	public static final <T> Tag<T> unmodifiableTag(final Tag<T> tag) {
		return new Tag<T>() {

			@Override public boolean hasParent() {
				return tag.hasParent();
			}

			@Override public Tag<?> getParent() {
				return unmodifiableTag(tag.getParent());
			}

			@Override public boolean hasChildren() {
				return tag.hasChildren();
			}

			@Override public TagGeneration<?> getChildren() {
				return unmodifiableGeneration(tag.getChildren());
			}

			@Override public TagGeneration<?> getGeneration() {
				return unmodifiableGeneration(tag.getGeneration());
			}

			@Override public TagSibling getSibling() {
				return unmodifiableSibling(tag.getSibling());
			}

			@Override public void setSibling(TagSibling sibling) {
				throw new UnsupportedOperationException();
			}

			@Override public void setValue(T value) {
				throw new UnsupportedOperationException();
			}

			@Override public T getValue() {
				return tag.getValue();
			}

			@Override public Class<T> getValueClass() {
				return tag.getValueClass();
			}

			@Override public void setName(String name) {
				throw new UnsupportedOperationException();
			}

			@Override public boolean canAdopt(Tag<?> child) {
				return false;
			}

			@Override public TagFactory<T> getFactory() {
				return tag.getFactory();
			}

			@Override public long size() {
				return tag.size();
			}

			@Override public void addListener(TagListener listener) {
				// redundant operation
			}

			@Override public void removeListener(TagListener listener) {
				// redundant operation
			}

			@Override public void broadcastEvent(TagEvent event) {
				// redundant operation
			}

			@Override public Tag<T> clone() {
				return unmodifiableTag(tag.clone());
			}
			
			@Override public boolean equals(Object o) {
				return ObjectUtils.equals(Tag.class, tag, o);
			}
			
		};
	}

}
